﻿// <copyright file="MachineVirtualRegistryData.cs" company="Sinclair Community College">
// Copyright 2010 Sinclair Community College
// </copyright>
// <originalAuthor>Patrick S. Seymour (patrick.seymour@gmail.com)</originalAuthor>

namespace SinclairCC.AppV
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// This class represents the machine (non-user) data section of a CP file.
    /// </summary>
    /// <remarks>
    /// This class corresponds to section 0x09 of a CP file.
    /// </remarks>
    internal class MachineVirtualRegistryData
    {
        /// <summary>
        /// The header for the section.
        /// </summary>
        private MachineVirtualRegistryDataHeader header;

        /// <summary>
        /// This list of registry entry blocks, which follow the header.
        /// </summary>
        private List<MachineVirtualRegistryEntry> entryBlocks;

        /// <summary>
        /// Initializes a new instance of the MachineVirtualRegistryData class.
        /// </summary>
        /// <param name="dataStream">
        /// A memory stream that contains the raw data for this section of the CP file.
        /// </param>
        public MachineVirtualRegistryData(System.IO.MemoryStream dataStream)
        {
            this.entryBlocks = new List<MachineVirtualRegistryEntry>();
            this.ReadSection(dataStream);
        }
        
        /// <summary>
        /// Reads the data for this section from the memory stream.
        /// </summary>
        /// <param name="dataStream">
        /// A memory stream containing the raw data for this section.
        /// </param>
        private void ReadSection(System.IO.MemoryStream dataStream)
        {
            System.IO.BinaryReader streamReader = new System.IO.BinaryReader(dataStream);

            // Read the section header.
            this.header = new MachineVirtualRegistryDataHeader(streamReader);

            // Read the registry entries.
            for (int i = 0; i < this.header.EntryCount; i++)
            {
                MachineVirtualRegistryEntry entry = new MachineVirtualRegistryEntry(dataStream);
                this.entryBlocks.Add(entry);
            }

            long stringTableStart = dataStream.Position;
            VirtualRegistryEntryValue valueData;

            // TODO: What do we do with the string/value table once it's read in?

            // Read the string/value table.
            foreach (MachineVirtualRegistryEntry entryBlock in this.entryBlocks)
            {
                valueData = null;
                if (entryBlock.HasValues && (entryBlock.ValueDataSize > 0))
                {
                    streamReader.BaseStream.Seek(stringTableStart + entryBlock.NameOffset, System.IO.SeekOrigin.Begin);
                    byte[] rawDataValue = streamReader.ReadBytes(entryBlock.NameSize);
                    string valueName = System.Text.Encoding.Unicode.GetString(rawDataValue, 0, rawDataValue.Length);

                    streamReader.BaseStream.Seek(stringTableStart + entryBlock.ValueDataOffset, System.IO.SeekOrigin.Begin);
                    rawDataValue = streamReader.ReadBytes(entryBlock.ValueDataSize);
                    switch (entryBlock.ValueType)
                    {
                        case Microsoft.Win32.RegistryValueKind.String:
                        case Microsoft.Win32.RegistryValueKind.MultiString:
                        case Microsoft.Win32.RegistryValueKind.ExpandString:
                            valueData = new VirtualRegistryEntryStringValue(rawDataValue);
                            break;
                        case Microsoft.Win32.RegistryValueKind.Binary:
                            valueData = new VirtualRegistryEntryBinaryValue(rawDataValue);
                            break;
                        case Microsoft.Win32.RegistryValueKind.DWord:
                            valueData = new VirtualRegistryEntryDWordValue(rawDataValue);
                            break;
                    }
                }
            }

            streamReader.Close();
        }
    }
}
